home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / Macintosh Sample Code / SC.021.ModalList / ModalList.c next >
Encoding:
C/C++ Source or Header  |  1989-09-30  |  17.9 KB  |  620 lines  |  [TEXT/MPS ]

  1. /*
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    ModalList : Simple Modal Dialog and List Manager Sample Application
  6. #
  7. #    ModalList.c
  8. #
  9. #    Copyright © 1989 Apple Computer, Inc.
  10. #    All rights reserved.
  11. #
  12. #    Versions:    
  13. #            1.00                     10/89
  14. #
  15. #    Components:
  16. #            ModalList.make            October 1, 1989
  17. #            ModalList.h                October 1, 1989
  18. #            ModalList.c                October 1, 1989
  19. #            ModalList.r                October 1, 1989
  20. #
  21. #    ModalList is an example application that demonstrates
  22. #    how to use the Dialog Manager and List Manager routines
  23. #    together. It is not a good example of a sample application
  24. #    but a great example of the use of lists in a dialog. The
  25. #    default LDEF is used to display a 2 dimensional list of strings.
  26. #    Each cell's string is initialized to represent it's position in the
  27. #    list. The user can change these strings and search for a particular
  28. #    setting. Once again this is not meant as an example application and
  29. #    there are some features that are documented in the source listing
  30. #    that you should pay close attention to inorder to understand how
  31. #    this example works.
  32. #
  33. */
  34.  
  35. #include <QuickDraw.h>
  36. #include <Fonts.h>
  37. #include <Controls.h>
  38. #include <Dialogs.h>
  39. #include <Windows.h>
  40. #include <TextEdit.h>
  41. #include <Memory.h>
  42. #include <Lists.h>
  43. #include <OSUtils.h>
  44. #include <SegLoad.h>
  45. #include <Packages.h>
  46. #include <ModalList.h>
  47.  
  48. /* Here are the prototypes.
  49. */
  50.  
  51. void                Initialize(void);
  52.  
  53. Boolean                MyList(void);                                /* Modal Dialog loop */
  54.  
  55. pascal void            MyItem(DialogPtr, short);                    /* Dialog Manger call backs */
  56. pascal Boolean        MyFilter(DialogPtr, EventRecord *, short);
  57.  
  58. pascal Boolean        MyClikLoop();                                 /* List Manger call backs */
  59. pascal short        MySearch(Ptr, Ptr, short, short);
  60.  
  61. void                LDeselect(ListHandle);                        /* utility routines */
  62. long                Cell2String(Point, char *);
  63.  
  64. /* This routine is part of the MPW runtime library. This external
  65. ** reference to it is done so that its segment can be unloaded, %A5Init.
  66. */
  67. extern void _DataInit();
  68.  
  69. #pragma segment Main
  70. main()
  71. {
  72.     UnloadSeg((Ptr) _DataInit);        /* note that _DataInit must not be in Main! */
  73.     
  74.     MaxApplZone();                    /* expand the heap so code segments load at the top */
  75.  
  76.     Initialize();
  77.     UnloadSeg((Ptr) Initialize);    /* note that Initialize must not be in Main! */
  78.  
  79.     (void) MyList();                /* this sample ignores the return value */
  80. }
  81.  
  82.  
  83. #pragma segment Initialize
  84. void Initialize()
  85. {
  86.     auto    EventRecord event;
  87.     auto    short        count;
  88.     auto    SysEnvRec    mac;
  89.     
  90.     InitGraf((Ptr) &qd.thePort);
  91.     InitFonts();
  92.     InitWindows();
  93.     TEInit();
  94.     InitDialogs(nil);
  95.     InitCursor();
  96.     
  97.     for (count = 1; count <= 3; count++)
  98.         EventAvail(everyEvent, &event);
  99.     
  100.     /* Make sure that the machine has at least 128K ROMs which includes the List Manager.
  101.     ** If it doesn't, exit.
  102.     */
  103.     SysEnvirons(cSysEnvironsVersion, &mac);
  104.     if (mac.machineType < 0)
  105.         ExitToShell();
  106. }
  107.  
  108. /* a utility routine to deselect all selected cells in the list.
  109. */
  110.  
  111. #pragma segment Main
  112. void LDeselect(list)
  113.             ListHandle    list;
  114. {
  115.     auto    Point        cell;
  116.     
  117.     /* start with the upper left cell
  118.     */
  119.     SetPt(&cell, 0, 0);
  120.     
  121.     /* for each selected cell
  122.     */
  123.     while(LGetSelect(true, &cell, list))
  124.         
  125.         /* deselect and unhilite it
  126.         */
  127.         LSetSelect(false, cell, list);
  128. }
  129.  
  130. /* a click loop procedure that does nothing but prove it can be done.
  131. */
  132.  
  133. #pragma segment Main
  134. pascal Boolean MyClikLoop()
  135. {
  136.     return true;
  137. }
  138.  
  139. /* a custom search procedure that is case sensitive. the standard list search procedure
  140. ** uses IUMagIDString which is case insensitive.
  141. */
  142.  
  143. #pragma segment Main
  144. pascal short MySearch(aPtr, bPtr, aLen, bLen)
  145.             Ptr            aPtr;        /* the cell data */
  146.             Ptr            bPtr;        /* the search pattern */
  147.             short        aLen;        /* the lengths */
  148.             short        bLen;
  149. {
  150.     return (0 != IUMagString(aPtr, bPtr, aLen, bLen));
  151. }
  152.  
  153. /* this routine will be called by the Dialog Manager to draw the outline of the
  154. ** default button and the list. 
  155. */
  156.  
  157. #pragma segment Main
  158. pascal void MyItem(dialog, itemNo)
  159.             DialogPtr    dialog;
  160.             short        itemNo;
  161. {
  162.     auto    short        itemType;
  163.     auto    Handle        itemHandle;
  164.     auto    Rect        itemRect;
  165.     
  166.     auto    ListHandle    list;
  167.     
  168.     GetDItem(dialog, itemNo, &itemType, &itemHandle, &itemRect);
  169.     switch(itemNo) {
  170.     
  171.     /* outline the default button (see IM I-407).  in this case it is the OK button.
  172.     ** this lets the user know that pressing the return will have the same effect as 
  173.     ** clicking this button.
  174.     */
  175.     case cOKOutlineItem :
  176.         PenSize(3, 3);
  177.         InsetRect(&itemRect, -4, -4);
  178.         FrameRoundRect(&itemRect, 16, 16);
  179.         PenSize(1, 1);
  180.         break;
  181.     
  182.     /* draw the list. the List Manager will draw the cells and scrollbars but does not
  183.     ** draw a border around the list's view rectangle, so it is done here also.
  184.     */
  185.     case cListItem :
  186.  
  187.         /* recover the list handle. it was stuffed into the dialog window's refCon
  188.         ** field when is was created.
  189.         */
  190.         list = (ListHandle) ((DialogPeek)dialog)->window.refCon;
  191.         
  192.         /* let the List Manager draw the list
  193.         */
  194.         LUpdate(dialog->visRgn, list);
  195.  
  196.         /* drawn the lists framing rectangle OUTSIDE the view rectangle.
  197.         ** if the frame is drawn inside the view rectangle then these lines
  198.         ** will be erased, drawn onto or scrolled by the List Manager since the lines
  199.         ** are within the rectangle LM expects to be able to draw in.
  200.         */
  201.         InsetRect(&itemRect, -1, -1);
  202.         FrameRect(&itemRect);
  203.         break;
  204.     }
  205. }
  206.  
  207. /* we need to be able to process mouse clicks in the list. the Dialog Manager makes this 
  208. ** possible through filter procedures like this one. since the default filter procedure
  209. ** will be replaced we also need to handle return key presses.
  210. */
  211.  
  212. #pragma segment Main
  213. pascal Boolean MyFilter(dialog, event, itemHit)
  214.             DialogPtr    dialog;
  215.             EventRecord    *event;
  216.             short        *itemHit;
  217. {
  218.     auto    ListHandle    list;
  219.     auto    Point        cell;
  220.     auto    char        character;
  221.     auto    Point        where;
  222.     auto    Rect        itemRect;
  223.     auto    short        itemType;
  224.     auto    Handle        itemHandle;
  225.     auto    Str255        string;
  226.     auto    short        length;
  227.  
  228.     switch (event->what) {
  229.     
  230.     /* watch for mouse clicks in the List
  231.     */
  232.     case mouseDown :
  233.         GetDItem(dialog, cListItem, &itemType, &itemHandle, &itemRect);
  234.         where = event->where;
  235.         GlobalToLocal(&where);
  236.         
  237.         /* if the user has clicked in the list then we'll handle the processing here
  238.         */
  239.         if (PtInRect(where, &itemRect)) {
  240.         
  241.             /* recover the list handle. it was stuffed into the dialog window's refCon
  242.             ** field when it was created.
  243.             */
  244.             list = (ListHandle) ((DialogPeek)dialog)->window.refCon;
  245.             
  246.             /* let the List Manager process the mouse down. this includes cell selection
  247.             ** dragging, scrolling and double clicks by the user.
  248.             */
  249.             if (LClick(where, event->modifiers, list)) {
  250.             
  251.                 /* a double click in a cell has occured.
  252.                 ** find out in which one of the cells the user has double clicked in.
  253.                 */
  254.                 cell = LLastClick(list);
  255.                 
  256.                 /* copy this cell's contents to the text edit box in the dialog
  257.                 */
  258.                 GetDItem(dialog, cTextItem, &itemType, &itemHandle, &itemRect);
  259.                 length = 255;
  260.                 LGetCell(&string[1], &length, cell, list);
  261.                 string[0] = (char) length;
  262.                 SetIText(itemHandle, string);
  263.             }
  264.             
  265.             /* tell the application that the list has been clicked in.
  266.             */
  267.             *itemHit = cListItem;
  268.             
  269.             /* tell the Dialog Manager that the event has been handled.
  270.             */
  271.             return true;
  272.         }
  273.         break;
  274.     
  275.     /* be sure and return this information so the Dialog Manager will process the 
  276.     ** return and enter key presses as clicks by the user in the OK button. this is
  277.     ** only required because we have overridden the Dialog Manager's default filtering.
  278.     */
  279.     case keyDown :    
  280.     case autoKey :
  281.         character = event->message;
  282.         if ('\n' == character) {
  283.  
  284.             /* tell the application that the OK button has been clicked by the user.
  285.             */
  286.             *itemHit = ok;
  287.             
  288.             /* tell the Dialog Manger that the event has been handled and the
  289.             ** character should not be added to the text edit field.
  290.             */
  291.             return true;
  292.         }
  293.         break;
  294.     }
  295.     
  296.     /* tell the Dialog Manger that the event has NOT been handled and that it should
  297.     ** take further action on this event.
  298.     */
  299.     return false;
  300. }
  301.  
  302. /* this routine will not return until the user has dismissed the modal dialog with
  303. ** a press of the return key or a click in the ok or cancel buttons. it displays a 
  304. ** list, check boxes for setting selection flags, a text edit field for searching and setting
  305. ** cell data and the usual ok and cancel buttons. the list uses the default LDEF procedure.
  306. **
  307. ** if you double click in a cell the cells contents will be moved to the
  308. ** text edit field. edit the field and click the set button and you will have edited the
  309. ** cell contents.
  310. **
  311. ** note that the Set button sets the last cell clicked in to the contents of the text edit field.
  312. ** it does not necessarily set the cell which is selected or hilited but it sets the cell that
  313. ** LLastClick returns. it is sort of a funky user interface but it does demonstrate the
  314. ** use of LLastClick.
  315. **
  316. ** if you scroll the list all the way to the right you will notice that there is some extra
  317. ** white space to the right of the right most cell. this was done intentionally to show what
  318. ** can happen when the lists viewing rectangle is not an even multiple of the cell rectangles.
  319. ** the List Manager must scroll this extra bit so that it can display the entire width of the
  320. ** right most cells. notice too that the bottom most cell does not display this behavior since
  321. ** the height of the list's viewing rectangle is an even multiple of the cell height.
  322. **
  323. ** note that a call to LSetSelect will select or hilite a cell which is empty even though 
  324. ** the list's selection flags field is set to lNoNilHilite. the selection flags
  325. ** are used only by the LClick routine they do not prevent the program from selecting 
  326. ** cells with LSetSelect in such a way that may seem inconsistent with their
  327. ** setting. this peculiarity can also happen with other selection flag settings and the
  328. ** LSetSelect call.
  329. **
  330. ** notice also that the column widths are all equal, there is no way to make cells with different 
  331. ** column widths using the List Manager.
  332. **
  333. ** there have been requests for the capability to have multiple lists displayed in a
  334. ** window and have them both scrolled by one scrollbar. the only way to accomplish this 
  335. ** would be to make new lists without the List Manager's scrollV or scrollH scrollbars.
  336. ** then create a new scrollbar using the Control Manager and setup an action procedure for
  337. ** TrackControl which calls LScroll for each of the lists. this is not demonstrated in
  338. ** this sample program.
  339. **
  340. */
  341.  
  342. #pragma segment Main
  343. Boolean MyList() {
  344.     auto    DialogPtr    dialog;            /* a dialog containing the list item */
  345.  
  346.     auto    short        itemNo;            /* the item in the dialog selected */
  347.     auto    short        itemType;        /* dummy parameter for call to GetDItem */
  348.     auto    Handle        itemHandle;        /* dummy parameter for call to GetDItem */
  349.     auto    Rect        itemRect;         /* the location of the list in the dialog */
  350.     
  351.     auto    ListHandle    list;            /* the list constructed in the dialog */
  352.     auto    Rect        dataBounds;        /* the dimensions of the data in the list */
  353.     auto    Point        cellSize;        /* width and height of a cells rectangle */
  354.     auto    Point        cell;            /* an index through the list */
  355.  
  356.     auto    char        string[255];
  357.     auto    short        length;
  358.     
  359.     auto    short        checked;        /* flag for setting and getting check box value */
  360.     auto    short        bit;            /* used as a mask to test the selection flags */ 
  361.     
  362.     /* create a new dialog window
  363.     */
  364.     dialog = GetNewDialog(cDLOGID, (Ptr) 0, (WindowPtr) -1);
  365.     SetPort((GrafPtr) dialog);
  366.         
  367.     /* set the procedure pointer for the user items in the dialog.
  368.     ** this will allow he default button to be outlined and the list to be drawn
  369.     ** by the Dialog Manger.
  370.     */
  371.     GetDItem(dialog, cOKOutlineItem, &itemType, &itemHandle, &itemRect);
  372.     SetDItem(dialog, cOKOutlineItem, itemType, (Handle) MyItem, &itemRect);
  373.     
  374.     GetDItem(dialog, cListItem, &itemType, &itemHandle, &itemRect);
  375.     SetDItem(dialog, cListItem, itemType, (Handle) MyItem, &itemRect);
  376.  
  377.     /* make room for scroll bars (see IM IV-270)
  378.     */
  379.      itemRect.right -= 15;
  380.      itemRect.bottom -= 15;
  381.  
  382.     /* create a list
  383.     */
  384.     SetRect(&dataBounds, 0, 0, cListCols, cListRows);
  385.     SetPt(&cellSize, cListCellWidth, cListCellHeight);
  386.     list = LNew(&itemRect, &dataBounds, cellSize, 0, (WindowPtr) dialog, false, false, true, true);
  387.  
  388.     /* allow the dialog manager routines to access the list record
  389.     */
  390.     ((DialogPeek)dialog)->window.refCon = (long) list;
  391.     
  392.     /* use the custom click loop procedure
  393.     */
  394.     (*list)->lClikLoop = (ProcPtr) MyClikLoop;
  395.  
  396.     /* use the default selection flags
  397.     */
  398.     (*list)->selFlags = 0;
  399.     
  400.     /* initialize the check boxes in the dialog according
  401.     ** to the settings of the list's selection flags
  402.     */
  403.     bit = 2;
  404.     itemNo = cNoNilHiliteItem;
  405.     while (itemNo <= cOnlyOneItem) {
  406.     
  407.         GetDItem(dialog, itemNo, &itemType, &itemHandle, &itemRect);
  408.          checked = ((*list)->selFlags == ((*list)->selFlags | bit)) ? 1 : 0;
  409.          SetCtlValue((ControlHandle) itemHandle, checked);
  410.         
  411.         bit *= 2;
  412.         ++itemNo;
  413.        }
  414.  
  415.     /* initialize the cell's contents.
  416.     */
  417.     for (cell.v = 0; cell.v < (**list).dataBounds.bottom; ++cell.v) {
  418.         for (cell.h = 0; cell.h < (**list).dataBounds.right; ++cell.h) {
  419.         
  420.             /* make a string representing the cell's position in the list.
  421.             */
  422.             length = Cell2String(cell, string);
  423.             
  424.             /* initialize the cell contents to this string.
  425.             **
  426.             ** you would initialize your cell data with what ever is appropriate
  427.             ** for your application here.
  428.             */
  429.             LSetCell(string, length, cell, list);
  430.         }
  431.     }
  432.     
  433.     /* turn cell drawing on only after the cell contents have been initialized.
  434.     ** this will avoid watching the delay between the LSetCells calls and is faster.
  435.     */
  436.     LDoDraw(true, list);
  437.     
  438.     do {
  439.     
  440.         /* process hits in the dialog.
  441.         */
  442.         ModalDialog(MyFilter, &itemNo);
  443.         
  444.         switch(itemNo) {
  445.  
  446.         /* process hits in the OK button.
  447.         */ 
  448.         case ok :
  449.         
  450.             /* find out which cells have been selected.
  451.             */
  452.             SetPt(&cell, 0, 0);
  453.             while(LGetSelect(true, &cell, list)) {
  454.             
  455.                 /* there is nothing to do with the user's selections in this sample
  456.                 ** so i'll just deselect the cells the users has selected.
  457.                 */
  458.                 LSetSelect(false, cell, list);
  459.             }
  460.             break;
  461.         
  462.         /* process hits in the Find button.
  463.         */ 
  464.         case cFindItem :
  465.         
  466.             GetDItem(dialog, cTextItem, &itemType, &itemHandle, &itemRect);
  467.             GetIText(itemHandle, string);
  468.             
  469.             /* search for a match in the list.
  470.             ** start the search at the upper left most cell in the list.
  471.             **
  472.             ** the List Manger performs the searchs row by row until it finds
  473.             ** the first match. this order can not be changed without writing a
  474.             ** replacement to LSearch, probably making use of LGetCell, LNextCell and
  475.             ** the International search routines.
  476.             */
  477.             SetPt(&cell, 0, 0);
  478.             
  479.             /* deselect all cells which are currently selected.
  480.             */
  481.             LDeselect(list);
  482.                 
  483.             /* use the custom search procedure.
  484.             ** the default search procedure is not case sensitive.
  485.             */
  486.             if (LSearch(&string[1], string[0], MySearch, &cell, list)) {
  487.             
  488.                 /* hilite the cell which contains the matching string.
  489.                 **
  490.                 ** note that this call will select or hilite a cell which is empty
  491.                 ** when the users search string is empty even though the list's
  492.                 ** selection flags field is set to lNoNilHilite. the selection flags
  493.                 ** are used only by the LClick routine they do not prevent the program
  494.                 ** from selecting cells with LSetSelect in such a way that may seem 
  495.                 ** inconsistent with their setting. this peculiarity can also happen
  496.                 ** with other selection flag settings and the LSetSelect call.
  497.                 */
  498.                 LSetSelect(true, cell, list);
  499.                 
  500.                 /* if the matching cell is not visible it will be scrolled into view.
  501.                 */
  502.                 LAutoScroll(list);
  503.             }
  504.             break;
  505.             
  506.         /* process hits in the Set button.
  507.         */ 
  508.         case cSetItem :
  509.             GetDItem(dialog, cTextItem, &itemType, &itemHandle, &itemRect);
  510.             GetIText(itemHandle, string);
  511.             
  512.             /* find out which was the last cell clicked in by the user.
  513.             ** not the last cell dragged into, or the last cell selected but the
  514.             ** last cell a mouse down event occured in.
  515.             */
  516.             cell = LLastClick(list);
  517.             if (0 <= cell.h && 0 <= cell.v) {
  518.             
  519.                 
  520.                 /* if a cell has been clicked in then deselect all cells which are
  521.                 ** currently selected.
  522.                 */
  523.                 LDeselect(list);
  524.  
  525.                 /* set the cell to the string the user has entered.
  526.                 */
  527.                 LSetCell(&string[1], string[0], cell, list);
  528.                 
  529.                 /* notice that this will Hilite an empty cell even with
  530.                 ** the list's selection flags set to lNoNilHilite.
  531.                 */
  532.                 LSetSelect(true, cell, list);
  533.  
  534.                 /* if the last cell clicked in is not visible it will be scrolled
  535.                 ** into view.
  536.                 */
  537.                 LAutoScroll(list);
  538.             }
  539.             break;
  540.             
  541.         /* process hits in the check boxes representing the list's selection flags.
  542.         */ 
  543.         case cOnlyOneItem :
  544.         case cExtendDragItem :
  545.         case cNoDisjointItem :
  546.         case cNoExtendItem :
  547.         case cNoRectItem :
  548.         case cUseSenseItem :
  549.         case cNoNilHiliteItem :
  550.         
  551.             /* deselect all cells which are currently selected.
  552.             */
  553.             LDeselect(list);
  554.             
  555.             /* toggle the check box.
  556.             */
  557.             GetDItem(dialog, itemNo, &itemType, &itemHandle, &itemRect);
  558.               checked = GetCtlValue((ControlHandle) itemHandle);
  559.               SetCtlValue((ControlHandle) itemHandle, !checked);
  560.  
  561.             /* adjust the selection flags to the users new settings.
  562.             */
  563.             switch (itemNo) {
  564.             case cOnlyOneItem :
  565.                 (*list)->selFlags ^= lOnlyOne; break;
  566.             case cExtendDragItem :
  567.                 (*list)->selFlags ^= lExtendDrag; break;
  568.             case cNoDisjointItem :
  569.                 (*list)->selFlags ^= lNoDisjoint; break;
  570.             case cNoExtendItem :
  571.                 (*list)->selFlags ^= lNoExtend; break;
  572.             case cNoRectItem :
  573.                 (*list)->selFlags ^= lNoRect; break;
  574.             case cUseSenseItem :
  575.                 (*list)->selFlags ^= lUseSense; break;
  576.             case cNoNilHiliteItem :
  577.                 (*list)->selFlags ^= lNoNilHilite; break;
  578.             }
  579.  
  580.             break;
  581.         }                
  582.     } while ((itemNo != ok) && (itemNo != cancel));
  583.     
  584.     /*  kill the list and dialog.
  585.     */
  586.     LDispose(list);
  587.     DisposDialog(dialog);
  588.     
  589.     /* return true if OK or RETURN key was hit.
  590.     */
  591.     return (ok == itemNo);
  592. }
  593.  
  594. /* just a funky routine to create strings for the cell's data
  595. */
  596. #pragma segment Main
  597. long Cell2String(pt, string)
  598.             Point        pt;
  599.             char         *string;
  600. {
  601.     auto    short        index;
  602.     auto    Str255        rowStr;
  603.     auto    Str255        colStr;
  604.     
  605.     NumToString((long)pt.v, rowStr);
  606.     *(string)++ = 'R';
  607.     for (index = 1; index <= rowStr[0]; ++index)
  608.         *(string++) = rowStr[index];
  609.         
  610.     *(string)++ = ',';
  611.     *(string)++ = ' ';
  612.  
  613.     NumToString((long)pt.h, colStr);
  614.     *(string)++ = 'C';
  615.     for (index = 1; index <= colStr[0]; ++index) 
  616.         *(string++) = colStr[index];
  617.     
  618.     return colStr[0] + rowStr[0] + 4;
  619. }
  620.